package wci.frontend.c.tokens;

import static wci.frontend.c.CErrorCode.INVALID_CHARACTER;
import static wci.frontend.c.CTokenType.ERROR;
import static wci.frontend.c.CTokenType.SPECIAL_SYMBOLS;
import wci.frontend.Source;
import wci.frontend.c.CToken;

/**
 * CSpecialSymbolToken
 * 
 * Used to represent special character tokens within C language
 * such as operators
 * @author James Foley
 */

public class CSpecialSymbolToken extends CToken
{

	/**
	 * simple constructor
	 */
	public CSpecialSymbolToken(Source source)
		throws Exception
	{
		super(source);
	}
	
    /**
     * Extract a C special symbol token from the source.
     * @throws Exception if an error occurred.
     */
    protected void extract()
        throws Exception
    {
        char currentChar = currentChar();

        text = Character.toString(currentChar);
        type = null;

        switch (currentChar) {

            // Single-character special symbols.
            case ',': case ';':  case '\'': case '(':  case ')':
            case '[':  case ']':  case '{':  case '}': case '~':
            case ':': case '.': case '?': case '@': case '\"':{
                nextChar();  // consume character
                break;
            }
            //& or && or &=
            case '&':{
            	currentChar = nextChar();  // consume '&';

                if (currentChar == '&') {
                    text += currentChar;
                    nextChar();  // consume '&'
                }else if (currentChar == '=') {
                	text += currentChar;
                	nextChar(); // consume '='
                }
            	break;
            }
            //* or *= or */
            case '*': {
            	currentChar = nextChar(); //consume '*'
            	
            	if (currentChar == '=') {
            		text += currentChar;
            		nextChar(); // consume '='
            	}else if (currentChar == '/') {
            		text  += currentChar;
            		nextChar(); //consume '/'
            	}
            	break;
            }
            // / or /= or // or /*
            case '/': {
            	currentChar = nextChar(); //consume '/'
            	
            	if (currentChar == '/') {
            		text += currentChar;
            		nextChar(); //consume '/'
            	}else if (currentChar == '=') {
            		text += currentChar;
            		nextChar(); // consume '='
            	}else if (currentChar == '*') {
            		text += currentChar;
            		nextChar(); // consume '*'
            	}
            	break;
            }
            // % or %=
            case '%': {
            	currentChar = nextChar(); // consume '%'
            	
            	if(currentChar == '=')
            	{
            		text += currentChar;
            		nextChar(); // consume '=';
            	}
            	break;
            }
            // ! or !=
            case '!': {
            	currentChar = nextChar(); // consume '!'
            	
            	if(currentChar == '=') {
            		text += currentChar;
            		nextChar(); // consume '=';
            	}
            	break;
            }
            // = or ==
            case '=': {
            	currentChar = nextChar(); // consume '='
            	
            	if(currentChar == '=') {
            		text += currentChar;
            		nextChar(); // consume '=';
            	}
            	break;
            }
            // | or |= or ||
            case '|': {
            	currentChar = nextChar(); // consume '|'
            	
            	if(currentChar == '=') {
            		text += currentChar;
            		nextChar(); // consume '=';
            	}else if(currentChar == '|')
            	{
            		text += currentChar;
            		nextChar(); // consume '|'
            	}
            	break;
            }
            // ^ or ^=
            case '^': {
            	currentChar = nextChar(); // consume '^'
            	
            	if(currentChar == '=') {
            		text += currentChar;
            		nextChar(); // consume '=';
            	}
            	break;
            }
            // + or ++ or +=
            case '+': {
            	currentChar = nextChar();  // consume '+';

                if (currentChar == '+') {
                    text += currentChar;
                    nextChar();  // consume '+'
                }else if (currentChar == '=') {
                	text += currentChar;
                	nextChar(); //consume '='
                }
                break;
            }
            //- or -- or -=
        	case '-':  {
            	currentChar = nextChar();  // consume '+';

                if (currentChar == '-') {
                    text += currentChar;
                    nextChar();  // consume '-'
                }else if (currentChar == '=') {
                	text += currentChar;
                	nextChar(); //consume '='
                }
                break;
            }
            // < or <= or << or <<=
            case '<': {
                currentChar = nextChar();  // consume '<';

                if (currentChar == '=') {
                    text += currentChar;
                    nextChar();  // consume '='
                }else if (currentChar == '<') {
                	text += currentChar;
                	currentChar = nextChar(); //consume '<'
                	if(currentChar == '=')
                	{
                		text += currentChar;
                		nextChar(); //consume '='
                	}
                }

                break;
            }

            // > or >= or >> or >>=
            case '>': {
                currentChar = nextChar();  // consume '>';

                if (currentChar == '=') {
                    text += currentChar;
                    nextChar();  // consume '='
                }else if (currentChar == '>') {
                	text += currentChar;
                	currentChar = nextChar(); //consume '>'
                	if(currentChar == '=')
                	{
                		text += currentChar;
                		nextChar(); //consume '='
                	}
                }

                break;
            }

            default: {
                nextChar();  // consume bad character
                type = ERROR;
                value = INVALID_CHARACTER;
            }
        }

        // Set the type if it wasn't an error.
        if (type == null) {
            type = SPECIAL_SYMBOLS.get(text);
        }
    }

}